#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <fstream>
#include <iostream>
#include <armadillo>
#include <iomanip>
#include <vector>

using namespace std;
using namespace arma;

const std::string  peopleList = "people_list.txt";


inline void test_gmm_model( field<string> peo_test, int run );
inline mat openCVtoArma( cv::Mat opencvMat );
inline cv::Mat ArmatoOpenCV(mat armaMat);


int
main(int argc, char** argv)
{
  
  ///Agregar cada Run
  ///Hacer lista de Acciones y de Personas
  ///Entrenar con 8 personas (single actions) y probar con una
  
  field<string> people;
  people.load(peopleList);
  //people.print("All People");
  

  cout << "Multi Action Classification " << endl;
  for (int r=1; r<=people.n_rows; r++)//people.n_rows
  {
    int run = r;
    
    cout << "****************************************" << endl;
    cout << "RUN: " << run << endl;
    cout << "****************************************" << endl;
    
    std::stringstream test_list;
    test_list<< "test_list_run"<< run << ".dat";
    
    
    field<string> peo_test;
    peo_test.load(  test_list.str() );
    
    cout << "Fusing SystemA and SystemB" << endl;
    test_gmm_model( peo_test, run );
  }
  
}

inline 
void 
test_gmm_model( field<string> peo_test, int run )
{
  
  double ave_acc=0;
  
  uvec real_labels;
  
 
   vec likelihood_actions;
   vec likelihood_label;
   likelihood_label << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9  << endr;
   
   mat log_probAB;

   mat log_probA, nor_log_probA;
   mat log_probB, nor_log_probB;
   
   
   
   
   
  for (uword vi = 0; vi <peo_test.n_rows; ++vi ){ 
    
   
    std::stringstream tmp_real_lab;
    tmp_real_lab<< "./real_labels/real_"<<peo_test(vi);  
    

    real_labels.load( tmp_real_lab.str(), raw_ascii );
    
    ///System A
    std::stringstream tmp_log_prob_sysA;
    tmp_log_prob_sysA<< "./SystemA/SystemA_log_prob_Run" << run << "_"<<peo_test(vi) << ".dat";  
    
    ///System B
    std::stringstream tmp_log_prob_sysB;
    tmp_log_prob_sysB<< "./SystemB/SystemB_log_prob_Run" << run << "_"<<peo_test(vi) << ".dat";
    

    
    log_probA.load( tmp_log_prob_sysA.str() , raw_ascii);
    log_probB.load( tmp_log_prob_sysB.str() , raw_ascii);
    
    //nor_log_probA.zeros(log_probA.n_rows, log_probA.n_cols);
    //nor_log_probB.zeros(log_probB.n_rows, log_probB.n_cols);
   
    
    
    
    ///Sumarlos columna por columna, pero antes normalizarlos
    
   int num_actions = log_probB.n_cols;
   
    ///Normalising
   //for (uword c=0; c<num_actions; ++c)
   //{
     
     //Doing for A
     //mat oneactionArma = log_probA.col(c);
     
     //cv::Mat oneactionCV = ArmatoOpenCV( oneactionArma );
     //cv::Mat oneaction_nor;
     //cv::normalize( oneactionCV, oneaction_nor, 0,1,cv::NORM_MINMAX );
     //mat oneactionArma_nor = openCVtoArma( oneaction_nor );
     //nor_log_probA.col(c) = oneactionArma_nor.col(0);
     
     //Doing for B
     //oneactionArma = log_probB.col(c);
     
     //oneactionCV = ArmatoOpenCV( oneactionArma );
     //cv::normalize( oneactionCV, oneaction_nor, 0,1,cv::NORM_MINMAX );
     //oneactionArma_nor = openCVtoArma( oneaction_nor );
     
     //nor_log_probB.col(c) = oneactionArma_nor.col(0);
//}
   ///end normalising
     
     //log_probA.save("probA.dat", raw_ascii);
     //log_probB.save("probB.dat", raw_ascii);
     //nor_log_probA.save("norm_probA.dat", raw_ascii);
     //nor_log_probB.save("norm_probB.dat", raw_ascii);
   
    //log_probAB = nor_log_probA + nor_log_probB;
   log_probAB = log_probA + log_probB;
    
    

    int num_frames = log_probB.n_rows;
    uvec est_labels(num_frames);
    
    //ADD probabilities
    //Primero probar como funciona cada una por separado. Ver si obtengo los mismos resultados que
    //en la tabla en Excel.
    for ( uword i = 0; i < num_frames; ++i)
    {
      uword index;
      double max_frame = log_probAB.row(i).max(index);
      est_labels(i) = likelihood_label(index);
      
    }
       
       
       ///Save???
       //std::stringstream tmp_save_estlab;
       //tmp_save_estlab<< "./run"<<run<<"/results/est_"<<peo_test(vi);  
       //est_labels.save(tmp_save_estlab.str(), raw_ascii);
    
       
       uvec comparing = find( est_labels == real_labels);
       double acc = comparing.n_elem;
       cout <<"performance for person "<<peo_test(vi)<<" is "<<setprecision(2)<<fixed<<100*acc/est_labels.n_elem << " %"<<endl;
       ave_acc = ave_acc + 100*acc/est_labels.n_elem;
       //getchar();
  }
  

  
}


inline
mat
openCVtoArma(cv::Mat opencvMat)
{
  int rows = opencvMat.rows;
  int cols = opencvMat.cols;
  cv::Mat matT(opencvMat.t());
  
  fmat armaConv(matT.ptr<float>(),rows, cols);
  
  mat armaMat = conv_to< mat >::from( armaConv );
  
  //cout << opencvMat << endl << endl;
  
  //cout << setprecision(2) << fixed << armaMat << endl;
  
 
  return armaMat;
}



inline
cv::Mat
ArmatoOpenCV(mat armaMat)
{
  //armaMat.print("armaMat");

  int rows = armaMat.n_rows;
  int cols = armaMat.n_cols;
  
  fmat armaMat_f = conv_to< fmat >::from( armaMat );
  
  
  cv::Mat opencvMatTmp(cols, rows, CV_32FC1, armaMat_f.memptr());
  cv::Mat opencvMat(opencvMatTmp.t());
 //std::cout << "opencvMat: " << std::endl << opencvMat << std::endl;
 
  return opencvMat;
}





